#include <iostream>
#include <memory>

using namespace std;


class Fruit{
public:
    virtual void name() = 0;
};

class Apple : public Fruit{
public:
    void name() override{
        cout << "apple " << endl;
    }
};


class Banana : public Fruit{
public:
    void name() override{
        cout << "banana " << endl;
    }
};

class Animal{
public:
    virtual void name() = 0;
};

class Cat : public Animal{
public:
    void name() override{
        cout << "cat " << endl;
    }
};

class Dog : public Animal{
public:
    void name() override{
        cout << "dog " << endl;
    }
};



//简单工厂
// class FruitFactory{
// public:
//     //返回一个智能指针
//     static shared_ptr<Fruit> create(const string& name){
//         if(name == "apple"){
//             // return shared_ptr<Apple>();
//             return make_shared<Apple>();
//         }else if(name == "banana"){
//             return make_shared<Banana>();
//         }
//     }
// };

// int main(){
//     //创建一个Fruit指针接收子类Apple的指针
//     shared_ptr<Fruit> fruit = FruitFactory::create("apple");
//     fruit->name();
//     fruit = FruitFactory::create("banana");
//     fruit->name();

//     return 0;
// }


// //工厂方法
// class FruitFactory{
// public:
//     virtual shared_ptr<Fruit> create() = 0;
// };

// class AppleFactory : public FruitFactory{
// public:
//     shared_ptr<Fruit> create() override{
//         return make_shared<Apple>();
//         // return shared_ptr<Apple>();
//     }
// };

// class BananaFactory : public FruitFactory{
// public:
//     shared_ptr<Fruit> create() override{
//         return make_shared<Banana>();
//     }
// };

// int main(){
//     //创建一个FruitFactory对象的指针接收子类AppleFactor对象的指针
//     shared_ptr<FruitFactory> ff(new AppleFactory());
//     //用工厂对象ff创建Apple对象
//     shared_ptr<Fruit> fruit = ff->create();
//     //用临时工厂对象AppleFactory()创建Apple对象
//     // shared_ptr<Fruit> fruit = AppleFactory().create();
//     fruit->name();

//     // 更改工厂对象ff所指向的工厂
//     // 不能直接将一个原始指针赋值给 ff
//     // ff = new BananaFactory();    //err
//     // ff = shared_ptr<FruitFactory>(new BananaFactory());
//     ff.reset(new BananaFactory());
//     fruit = ff->create();
//     fruit->name();
//     return 0;
// }


//抽象工厂
//抽象超级工厂
class Factory {
public:
    //传入水果名生产对应的水果
    virtual shared_ptr<Fruit> getFruit(const string &name) = 0;
    //传入动物名生产对应的动物
    virtual shared_ptr<Animal> getAnimal(const string &name) = 0;

};

class FruitFactory : public Factory{
public:
    // 返回一个空的智能指针
    shared_ptr<Animal> getAnimal(const string &name) override{
        // return nullptr;
        // return shared_ptr<Animal>(nullptr);
        return shared_ptr<Animal>();
    }

    //生产具体的水果
    shared_ptr<Fruit> getFruit (const string &name) override{
        cout << "FruitFactory ";
        if(name == "apple"){
            // return shared_ptr<Apple>();
            return make_shared<Apple>();
        }else if(name == "banana"){
            return make_shared<Banana>();
        }
    }


};


class AnimalFactory : public Factory{
public:
    // 返回一个空的智能指针
    shared_ptr<Fruit> getFruit (const string &name) override{
        return nullptr;
    }

    //生产具体的动物
    shared_ptr<Animal> getAnimal(const string &name) override{
        cout << "AnimalFactory ";
        if(name == "cat"){
            // return shared_ptr<Apple>();
            return make_shared<Cat>();
        }else if(name == "dog"){
            return make_shared<Dog>();
        }
    }
};

//工厂的生产者
class FactoryProducer{
public:
    //加static就不用实例化了，直接使用命名空间就行
    static shared_ptr<Factory> create(const string& name){
        cout << "Factory ";
        if(name == "fruit"){
            return make_shared<FruitFactory>();
        }else if(name == "animal"){
            return make_shared<AnimalFactory>();
        }
    }
};

int main(){
    //工厂的生产者创建一个抽象超级工厂factory，并且赋予fruit属性，实际上就是生产了一个fruitfactory超级工厂
    shared_ptr<Factory> factory = FactoryProducer::create("fruit");
    //超级工厂fruitfactory构造简单工厂apple(factory)，同时简单工厂进行具体的产品生产，并返回所生产的产品
    shared_ptr<Fruit> fruit = factory->getFruit("apple");
    fruit->name();
    fruit = factory->getFruit("banana");
    fruit->name();

    factory = FactoryProducer::create("animal");
    shared_ptr<Animal> Animal = factory->getAnimal("cat");
    Animal->name();
    Animal = factory->getAnimal("dog");
    Animal->name();
    

}
